package io.oschina.binv.kapp.framework

import android.Manifest
import android.annotation.TargetApi
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.support.v7.app.AlertDialog
import android.view.KeyEvent
import com.umeng.analytics.MobclickAgent
import io.reactivex.ObservableTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlin.properties.Delegates
import com.alibaba.sdk.android.man.MANServiceProvider
import com.trello.rxlifecycle2.RxLifecycle
import com.trello.rxlifecycle2.android.ActivityEvent
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity
import io.oschina.binv.kapp.BuildConfig
import io.oschina.binv.kapp.framework.utils.Logger
import io.oschina.binv.kapp.framework.extend.printOrReport
import io.reactivex.functions.Consumer

/**
 * Created by xuybin on 2017/7/25.
 */
abstract class BaseActivity : RxAppCompatActivity() {
    val Log = Logger(this::class.java.canonicalName)
    fun <T> ioToMain(): ObservableTransformer<T, T> {
        return ObservableTransformer { upstream ->
            upstream.compose(RxLifecycle.bindUntilEvent(lifecycle(), ActivityEvent.DESTROY)).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        }
    }
    companion object {
       data class FinishEvent(val canonicalName:String, val args:String="")
    }
    init {
        //必须放置此处,否则因为用户操作,或androi生命周期原因会多次执行,导致内存泄露(DESTROY后,才会销毁)
        RxBus.toObservable(FinishEvent::class.java)
                .compose(ioToMain())
                .subscribe(Consumer {
                    data->
                    Log.i(data.toString())
                    if(data.canonicalName==this::class.java.canonicalName && data.args.isEmpty()){
                        finish()
                    }
                },Consumer {
                    ex->this.printOrReport(ex)
                })
    }
    /**********以下重新定义********/
    abstract fun setContentView()

    /*
     * * 把不属于强制生命周期的onRestoreInstanceState和onSaveInstanceState转换为强制生命周期
     * * 外部传递的参数或内部运行中产生的状态.返回函数用于保存
     */
    abstract fun initViewsAndLocalData(savedIntent: Intent): (outIntent: Intent) -> Unit

    abstract fun loadRemoteData()
    /********** 以上重新定义********/

    var saveArgsOrStatus by Delegates.notNull<(intent: Intent) -> Unit>()

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.i("onCreate")
        super.onCreate(savedInstanceState)

        try {
            //串联,前一个出错,后一个不执行
            setContentView()
            if (intent == null) intent = Intent()
            saveArgsOrStatus = initViewsAndLocalData(intent)
        } catch (ex: Throwable) {
            this.printOrReport(ex)
            finish()
        }
        try {
            loadRemoteData()
        } catch (ex: Throwable) {
            this.printOrReport(ex)
        }
    }

    override fun onStart() {
        Log.i("onStart")
        super.onStart()
    }

    //不属于强制生命周期,系统按需调用
    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        Log.i("onRestoreInstanceState")
        super.onRestoreInstanceState(savedInstanceState)
    }

    /*
     * 传Intent数据给Activity时，此Activity为singleInstance ，在onResume中无法获取传入的Intent,原来用getIntent()只能获取Activity原来的Intent.
     * 有此方法可以让singleInstance的Activity获取传入的Intent,并获取Extra数据：
     */
    override fun onNewIntent(otherIntent: Intent) {
        Log.i("onNewIntent()")
        super.onNewIntent(otherIntent)
        intent = otherIntent

        try {
            //串联,前一个出错,后一个不执行
            if (intent == null) intent = Intent()
            saveArgsOrStatus = initViewsAndLocalData(intent)
        } catch (ex: Throwable) {
            this.printOrReport(ex)
            finish()
        }
        try {
            loadRemoteData()
        } catch (ex: Throwable) {
            this.printOrReport(ex)
        }
    }

    override fun onResume() {
        Log.i("onResume")
        super.onResume()
        MobclickAgent.onResume(this)
        MANServiceProvider.getService().manPageHitHelper.pageAppear(this)
    }

    //不属于强制生命周期,系统按需调用
    override fun onSaveInstanceState(outState: Bundle) {
        Log.i("onSaveInstanceState")
        try {
            if (intent == null) intent = Intent()
            saveArgsOrStatus(intent) //只保存intent传递过来的值被修改后,覆盖原值
        } catch (ex: Throwable) {
            this.printOrReport(ex)
        }
        super.onSaveInstanceState(outState)
    }

    override fun onPause() {
        Log.i("onPause")
        super.onPause()
        MobclickAgent.onPause(this)
        MANServiceProvider.getService().manPageHitHelper.pageDisAppear(this)
    }

    override fun onStop() {
        Log.i("onStop")
        super.onStop()
    }

    override fun onDestroy() {
        Log.i("onDestroy")
        super.onDestroy()
    }

    //data一定声明为Intent?,而不能是Intent否则,直接结束,未调用setResult,会调用了setResult但未给Intent时都会崩溃
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.i("onActivityResult")
        super.onActivityResult(requestCode, resultCode, data)
    }
    /**********以下辅助函数********/
    var beforeFinishing=false //防止多次点击
    var beforeFinishingKey=false //防止多次点击
    private class BeforeFinish(val run: () -> Unit)
    private val beforeFinishRuns= mutableListOf<BeforeFinish>()

    //不能有阻塞调用，否则导致退出不了;内部不能有finish调用会造成死循环
    fun beforeFinishRunAsync(run:()->Unit){
        beforeFinishRuns.add(BeforeFinish(run))
    }

    //只能配对使用，才能达到效果
    //Fragments.beforeFinishRunAsync->Fragments.finish()
    //Activity.beforeFinishRunAsync->Activity.finish()
    override fun finish(){
        if (beforeFinishing){
            return
        }
        beforeFinishing=true
        try{
            beforeFinishRuns.forEach { b->b.run() }
        }catch (ex:Throwable){
            this.printOrReport(ex)
        }
        super.finish()
    }

    override fun onBackPressed() {
        if (!beforeFinishingKey){
            beforeFinishingKey=true
            //只处理物理按键的退出，需要透传到fragments，在Activity明确调用finish()的不做处理
            //只能配对使用
            //Fragments.beforeFinishRunAsync->Fragments.finish()
            //Activity.beforeFinishRunAsync->Activity.finish()
            val  fragments= supportFragmentManager.fragments
            try{
                if (fragments!=null ){
                    fragments.forEach { fragment->
                        if(fragment is BaseFragment){
                            fragment.finish(true)
                        }
                    }
                }
            }catch (ex:Throwable){
                this.printOrReport(ex)
            }
            finish()
            //或super.onBackPressed()
        }
    }

    /**********以下异步请求授权,并执行相关内容********/
    private class RequestPermission(val permissions: Array<String>
                                    , val hasDeniedPermissions: Array<String>
                                    , val onPermissionsDenied: (deniedPermissions: Array<String>, isShowRequestPermissionRationale: Boolean) -> Unit
                                    , val onPermissionsGranted: () -> Unit) {
        /** 只要文件的路径相同，就认为是相同的文件  */
        override fun equals(o: Any?): Boolean {
            try {
                val other = o as RequestPermission
                return this.permissions == other.permissions && this.onPermissionsGranted == other.onPermissionsGranted
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
            return super.equals(o)
        }



        companion object {
            fun permissionsDesc(permissions: Array<String>): Array<String> {
                val permissionsDescSet = mutableSetOf<String>()
                permissions.forEach { p ->
                    when (p) {
                        Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE -> permissionsDescSet.add("存储卡")
                        Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR -> permissionsDescSet.add("日历")
                        Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, Manifest.permission.GET_ACCOUNTS -> permissionsDescSet.add("联系人")
                        Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION -> permissionsDescSet.add("位置")
                        Manifest.permission.RECORD_AUDIO -> permissionsDescSet.add("麦克风")
                        Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE, Manifest.permission.READ_CALL_LOG, Manifest.permission.WRITE_CALL_LOG
                            , Manifest.permission.ADD_VOICEMAIL, Manifest.permission.USE_SIP, Manifest.permission.PROCESS_OUTGOING_CALLS -> permissionsDescSet.add("电话")
                        Manifest.permission.BODY_SENSORS -> permissionsDescSet.add("传感器")
                        Manifest.permission.SEND_SMS, Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_WAP_PUSH,
                        Manifest.permission.RECEIVE_MMS -> permissionsDescSet.add("短信")
                        Manifest.permission.CAMERA -> permissionsDescSet.add("摄像头")
                    }
                }
                return permissionsDescSet.toTypedArray()
            }
        }
    }

    private val requestPermissionMap = mutableMapOf<Int, RequestPermission>()
    private var permissionRequestCode = 23000

    //默认的请求时提示
    @TargetApi(Build.VERSION_CODES.M)
    protected fun onShowPermissionRationaleDefault(requestCode: Int, needPermissions: Array<String>) {
        var needPermissionsDesc = "["
        RequestPermission.permissionsDesc(needPermissions).forEach { p ->
            needPermissionsDesc += ",$p"
        }
        needPermissionsDesc += "]"

        val alertBuilder = AlertDialog.Builder(this)
        alertBuilder.setCancelable(false)
        alertBuilder.setTitle("请求允许权限,否则影响部分功能使用")
        alertBuilder.setMessage("请求${needPermissionsDesc}相关权限,清选择允许")
        alertBuilder.setPositiveButton("知道了") { dialog, which ->
            requestPermissions(needPermissions, requestCode)
            dialog.dismiss()
        }
        alertBuilder.create().show()
    }

    //默认的拒绝时提示
    protected fun onPermissionsDeniedDefault(deniedPermissions: Array<String>, isShowRequestPermissionRationale: Boolean) {
        var deniedPermissionsDesc = "["
        RequestPermission.permissionsDesc(deniedPermissions).forEach { p ->
            deniedPermissionsDesc += ",$p"
        }
        deniedPermissionsDesc += "]"
        val alertBuilder = AlertDialog.Builder(this)
        alertBuilder.setCancelable(false)
        alertBuilder.setTitle("需允许权限,否则影响部分功能使用")
        if (isShowRequestPermissionRationale) {
            alertBuilder.setMessage("刚禁止了${deniedPermissionsDesc}相关权限,请设置为允许")
        } else {
            alertBuilder.setTitle("需允许权限,否则影响部分功能使用")
            alertBuilder.setMessage("以往禁止了${deniedPermissionsDesc}相关权限,请设置为允许")
        }
        alertBuilder.setPositiveButton("去设置") { dialog, which ->
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            intent.data = Uri.parse("package:" + BuildConfig.APPLICATION_ID) // 根据包名打开对应的设置界面
            this.startActivity(intent)
            dialog.dismiss()
        }
        alertBuilder.setNegativeButton("取消") { dialog, which ->
            dialog.dismiss()
        }
        alertBuilder.create().show()
    }

    //给子类使用的,公开方法
    @TargetApi(Build.VERSION_CODES.M)
    protected fun requestPermissionRunAsync(permissions: Array<String>
                                     , onShowPermissionRationale: (requestCode: Int, needPermissions: Array<String>) -> Unit = { r, p -> onShowPermissionRationaleDefault(r, p) }
                                     , onPermissionsDenied: (deniedPermissions: Array<String>, isShowRequestPermissionRationale: Boolean) -> Unit = { p, s -> onPermissionsDeniedDefault(p, s) }
                                     , onPermissionsGranted: () -> Unit) {
        val currentAPIVersion = Build.VERSION.SDK_INT
        if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) {
            //已被禁止的和需要请求的
            val hasDeniedPermissions = mutableListOf<String>()
            val needPermissions = mutableListOf<String>()
            permissions.forEach { permission ->
                if (this.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                    //检查权限申请框是否会显示
                    if (shouldShowRequestPermissionRationale( permission)) {
                        //需要请求的
                        needPermissions.add(permission)
                    } else {
                        //已被禁止的
                        hasDeniedPermissions.add(permission)
                    }

                } else {
                    onPermissionsGranted()
                }
            }

            if (needPermissions.size > 0) {
                //还有权限需要请求,更新请求码
                permissionRequestCode++
                onShowPermissionRationale(permissionRequestCode, needPermissions.toTypedArray())
                val requestPermission = RequestPermission(needPermissions.toTypedArray(), hasDeniedPermissions.toTypedArray(), onPermissionsDenied, onPermissionsGranted)
                //不重复添加 key 是requestCode
                if (!requestPermissionMap.values.contains(requestPermission)) requestPermissionMap.put(permissionRequestCode, requestPermission)
            } else if(hasDeniedPermissions.size>0){
                //全部权限已被禁止
                onPermissionsDenied(hasDeniedPermissions.toTypedArray(), false)
            }
        } else {
            onPermissionsGranted()
        }
    }

    //处理权限请求回调,不允许再继承
    final override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestPermissionMap.containsKey(requestCode)) {
            val deniedPermissions = mutableListOf<String>()
            permissions.forEachIndexed { i, permission ->
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) deniedPermissions.add(permission)
            }
            deniedPermissions.addAll(requestPermissionMap[requestCode]!!.hasDeniedPermissions)
            if (deniedPermissions.size > 0) {
                //有部分拒绝
                requestPermissionMap[requestCode]!!.onPermissionsDenied(deniedPermissions.toTypedArray(), true)
            } else {
                //全部允许
                requestPermissionMap[requestCode]!!.onPermissionsGranted()
            }
            //处理完回调,销毁改对象
            requestPermissionMap.remove(requestCode)
        }
    }
}